#include <core.h>
#include <stdint.h>
#include <FreeRTOS.h>
#include <task.h>
#include <interrupt.h>

#ifdef configISR_STACK_SIZE_WORDS
	unsigned int __freertos_irq_stack_top[256];
#endif

void freertos_risc_v_application_interrupt_handler(uint32_t ulMcause)
{
	uint32_t cause, mip, mie;
	uint32_t pending = 0;
	int intc;

	/**
	 * Mailbox: 16
	 * EXT INT: 11
	 * SOFT INT: 3
	 * Timer INT: 7 被汇编函数接管。这里不会处理.
	 * */
	cause = read_csr(mcause);
	mip = read_csr(mip);
	mie = read_csr(mie);
	pending = mie & mip;
	intc = pending & (1 << (IRQ_RISCV_INTC - IRQ_CPU_BASE));
	/* printk("### mcause = 0x%x, mip = 0x%x, mie = 0x%x\n",cause, mip, mie); */
	if (intc) {
		handle_irq(IRQ_RISCV_INTC);
	} else if (pending & (1 << (IRQ_RISCV_MAILBOX - IRQ_CPU_BASE))) {
		handle_irq(IRQ_RISCV_MAILBOX);
	}
}

volatile int dump_stack_top = 0;
extern void printk(const char *fmt, ...);
extern uint32_t *pxCurrentTCB;

static void dump_register(uint32_t *addr)
{
	printk("EPC:0x%08x ra:0x%08x t0:0x%08x t1:0x%08x t2:0x%08x s0:0x%08x s1:0x%08x \n",
			addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
	printk("a0:0x%08x a1:0x%08x a2:0x%08x a3:0x%08x a4:0x%08x a5:0x%08x a6:0x%08x \n",
			addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
	printk("a7:0x%08x s2:0x%08x s3:0x%08x s4:0x%08x s5:0x%08x s6:0x%08x s7:0x%08x \n",
			addr[16], addr[17], addr[18], addr[19], addr[20], addr[21], addr[22], addr[23]);
	printk("s8:0x%08x s9:0x%08x s10:0x%08x s11:0x%08x t3:0x%08x t4:0x%08x t5:0x%08x \n",
			addr[24], addr[25], addr[26], addr[27], addr[28], addr[29], addr[30], addr[31]);
	printk("t6:0x%08x CRN:0x%08x MST:0x%08x \n",
			addr[32], addr[33]);
}
static void dump_addr_data(uint32_t *addr, int szWords)
{
	for (int i = 0; i < szWords; i++) {
		if ((i % 8) == 0) {
			printk("%p: ", addr + i);
		}
		printk(" 0x%08x", *(addr + i));
		if ((i % 8) == 7) {
			printk("\n");
		}
	}
}
// void *pcTaskStackStart(TaskHandle_t xTaskToQuery);
static void dump_stack()
{
	uint32_t *tcb = (uint32_t *)pxCurrentTCB;
	uint32_t *sp = (uint32_t *)tcb[0];
	printk("Task Name: %s\n", pcTaskGetName((TaskHandle_t)pxCurrentTCB));
	//    printk("Task start: %p\n", pcTaskStackStart((TaskHandle_t)pxCurrentTCB));
	printk("------------- register dump sp:[%p]---------------\n", sp);
	dump_register(sp);
	printk("------------- stack dump ---------------\n");
	dump_addr_data(sp - 32, 32);
	printk("------------- --------- ---------------\n");
	dump_addr_data(sp + 32, 32);
}

void xTaskIncrementTick_call()
{
	if (dump_stack_top) {
		dump_stack();
	}
}


void freertos_risc_v_application_exception_handler(uint32_t ulMcause)
{
	volatile uint32_t ulMEPC = 0UL, ulMCAUSE = 0UL;
	(void) ulMCAUSE;

	/* Store a few register values that might be useful when determining why this
	 * function was called.
	 * */
	__asm volatile("csrr %0, mepc" : "=r"(ulMEPC));
	__asm volatile("csrr %0, mcause" : "=r"(ulMCAUSE));

	printk("---- exception hanppend, ulMEPC: %x, ulMcause: %x\n", ulMEPC, ulMCAUSE);
	dump_stack();
	asm volatile("nop");
	while (1);
}
